#include	"../core/response.h"
#include	"../utils/logger.h"
#include	"../utils/utils.h"
#include    "../utils/datetime.h"

#include    <microhttpd.h>

extern "C" {
#include	<luajit.h>
#include	<lualib.h>
#include	<lauxlib.h>
}

extern std::string lua_tojson(lua_State *, int);

namespace {

    static int Header(lua_State * lua) {
		if (!lua_isuserdata(lua, 1)) {
			Logger::Instance().Error("Please using rsp:header() instead of rsp.header()");
			return 0;
		}

        Response * rsp = *(Response **)lua_topointer(lua, 1);
        const char * key = lua_tostring(lua, 2);
        const char * val = lua_tostring(lua, 3);
        rsp->Header(key, val);
        return 0;
    }

    static int Cookie(lua_State * lua) {
		if (!lua_isuserdata(lua, 1)) {
			Logger::Instance().Error("Please using rsp:cookie() instead of rsp.cookie()");
			return 0;
		}

        Response * rsp = *(Response **)lua_topointer(lua, 1);
        int top = lua_gettop(lua);

        std::string header;
        header.append(lua_tostring(lua, 2));
        header.append("=");
        header.append(lua_tostring(lua, 3));
        header.append(";");

        if (top > 3) {
            int expire = lua_tointeger(lua, 4);
            time_t now = time(NULL);

            header.append("expires=");
            header.append(GMTime(now + expire).c_str());
            header.append(";");
        }

        if (top > 4) {
            header.append("path=");
            header.append(lua_tostring(lua, 5));
            header.append(";");
        }

        rsp->Cookie(header);
        return 0;
    }

    static int Echo(lua_State * lua) {
		if (!lua_isuserdata(lua, 1)) {
			Logger::Instance().Error("Please using rsp:echo() instead of rsp.echo()");
			return 0;
		}

        Response * rsp = *(Response **)lua_topointer(lua, 1);
        size_t size = 0;
        const char * data = lua_tolstring(lua, 2, &size);
        rsp->Echo(std::string(data, size));
        return 0;
    }

    static int Error(lua_State * lua) {
		if (!lua_isuserdata(lua, 1)) {
			Logger::Instance().Error("Please using rsp:error() instead of rsp.error()");
			return 0;
		}

        Response * rsp = *(Response **)lua_topointer(lua, 1);
        rsp->Error(lua_tointeger(lua, 2));
        return 0;
    }

    static int Redirect(lua_State * lua) {
		if (!lua_isuserdata(lua, 1)) {
			Logger::Instance().Error("Please using rsp:redirect() instead of rsp.redirect()");
			return 0;
		}

        Response * rsp = *(Response **)lua_topointer(lua, 1);
        rsp->Redirect(lua_tostring(lua, 2));
        return 0;
    }

    static int Html(lua_State * lua) {
		if (!lua_isuserdata(lua, 1)) {
			Logger::Instance().Error("Please using rsp:html() instead of rsp.html()");
			return 0;
		}

        Response * rsp = *(Response **)lua_topointer(lua, 1);
        rsp->Header(MHD_HTTP_HEADER_CONTENT_TYPE, "text/html");

        int top = lua_gettop(lua);

		lua_getglobal(lua, "debug");
		lua_getfield(lua, -1, "traceback");
		lua_remove(lua, -2);

		lua_getglobal(lua, "template");
		lua_getfield(lua, -1, "render");
		lua_remove(lua, -2);

		lua_pushvalue(lua, 1);
		lua_pushvalue(lua, 2);
		if (top > 2) lua_pushvalue(lua, 3);
		if (top > 3) lua_pushvalue(lua, 4);

		if (lua_pcall(lua, top, 0, top + 1) != 0) {
			Logger::Instance().Error("Failed to compile html : %s", lua_tostring(lua, -1));
		}

		return 0;
    }

    static int Json(lua_State * lua) {
		if (!lua_isuserdata(lua, 1)) {
			Logger::Instance().Error("Please using rsp:json() instead of rsp.json()");
			return 0;
		}

        Response * rsp = *(Response **)lua_topointer(lua, 1);
		rsp->Echo(lua_tojson(lua, 2));
		if (lua_gettop(lua) < 3 || lua_toboolean(lua, 3)) rsp->Header(MHD_HTTP_HEADER_CONTENT_TYPE, "application/json");		
		return 0;
    }

	static int File(lua_State * lua) {
		if (!lua_isuserdata(lua, 1)) {
			Logger::Instance().Error("Please using rsp:file() instead of rsp.file()");
			return 0;
		}

        Response * rsp = *(Response **)lua_topointer(lua, 1);
		rsp->File(lua_tostring(lua, 2));	
		return 0;
	}
}

void RegisterApi_Response(lua_State * lua) {
    luaL_newmetatable(lua, "__omni_response");
	lua_pushvalue(lua, -1);
	lua_setfield(lua, -2, "__index");

    lua_pushcfunction(lua, &Header);
	lua_setfield(lua, -2, "header");
    
	lua_pushcfunction(lua, &Cookie);
	lua_setfield(lua, -2, "cookie");
    
    lua_pushcfunction(lua, &Echo);
	lua_setfield(lua, -2, "echo");

	lua_pushcfunction(lua, &Error);
	lua_setfield(lua, -2, "error");

	lua_pushcfunction(lua, &Redirect);
	lua_setfield(lua, -2, "redirect");

	lua_pushcfunction(lua, &Html);
	lua_setfield(lua, -2, "html");

	lua_pushcfunction(lua, &Json);
	lua_setfield(lua, -2, "json");

	lua_pushcfunction(lua, &File);
	lua_setfield(lua, -2, "file");

	lua_pop(lua, 1);
}